package net.keebook.webapp.ws;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Properties;
import java.util.TimeZone;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.log4j.Logger;

@WebServlet(urlPatterns="/js/*")
public class JavaScriptServlet extends HttpServlet {
	private static final long serialVersionUID = 6403824553109949675L;
	private String js;
	private String lastModified = "";
	
	@Override
	public void init() throws ServletException {
		super.init();
		rebuild(true);
	}
	
	private synchronized String compileJavascript(String jsCode) {
		try {
			List<NameValuePair> params = new ArrayList<NameValuePair>();
			params.add(new BasicNameValuePair("js_code", jsCode));
			params.add(new BasicNameValuePair("compilation_level", "SIMPLE_OPTIMIZATIONS"));
			params.add(new BasicNameValuePair("output_format", "text"));
			params.add(new BasicNameValuePair("output_info", "compiled_code"));
			
			HttpPost httpPost = new HttpPost("http://closure-compiler.appspot.com/compile");
			httpPost.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));
			
			HttpClient httpClient = new DefaultHttpClient();
			HttpResponse response = httpClient.execute(httpPost);
			
			if (response.getStatusLine().getStatusCode() == 200) {
				HttpEntity entity = response.getEntity();
				InputStream inputStream = entity.getContent();
				
				ByteArrayOutputStream content = new ByteArrayOutputStream();
				int readBytes = 0;
				byte[] sBuffer = new byte[512];
				while ((readBytes = inputStream.read(sBuffer)) != -1) {
					content.write(sBuffer, 0, readBytes);
				}
				
				String responseString = new String(content.toByteArray(), "UTF-8");
				return responseString;
			} else {
				Logger.getLogger(this.getClass()).error("Got invalid http response code from closure compiler service: " + response.getStatusLine().getStatusCode());
				return jsCode;
			}
		} catch (IOException e) {
			Logger.getLogger(this.getClass()).error("Exception while communicating with closure compiler service", e);
			return jsCode;
		}
	}
	
	private synchronized void rebuild(boolean compile) {
		List<String> jsFiles = getJsFiles();
		StringBuilder sb = new StringBuilder();
		
		
		for (String jsFilename : jsFiles) {
			try {
				InputStream in = getServletContext().getResourceAsStream("/WEB-INF"+jsFilename);
				String content = getJsFileContent(in);
				sb.append(content);
				sb.append("\n");
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		
		if (compile) {
			js = compileJavascript(sb.toString());
		} else {
			js = sb.toString();
		}
		
		DateFormat httpDateFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
        httpDateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
		setLastModified(httpDateFormat.format(new Date()));
	}
	
	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		response.setContentType("text/javascript");
		response.setCharacterEncoding("UTF-8");
		PrintWriter out = response.getWriter();
		if ("1".equals(request.getParameter("rebuild"))) {
			rebuild(false);
		}
		response.setHeader("Last-Modified", getLastModified());
		out.print(getJs());
		out.flush();
	}
	
	public String getJs() {
		return js;
	}

	
	private String getJsFileContent(InputStream in) throws IOException {
		StringBuffer fileData = new StringBuffer(1000);
        BufferedReader reader = new BufferedReader(new InputStreamReader(in, "UTF-8"));
        char[] buf = new char[1024];
        int numRead=0;
        while((numRead=reader.read(buf)) != -1){
            fileData.append(buf, 0, numRead);
        }
        reader.close();
        return fileData.toString();
	}
	
	private List<String> getJsFiles() {
		List<String> result = new ArrayList<String>();
		Properties properties = new Properties();
		try {
			properties.load(getClass().getResourceAsStream("/javascript.properties"));
		} catch (IOException e) {
			e.printStackTrace();
			return result;
		}
		
		int i = 1;
		while (properties.containsKey("file"+i)) {
			result.add(properties.getProperty("file"+i));
			i++;
		}
		
		return result;
	}

	public String getLastModified() {
		return lastModified;
	}

	public void setLastModified(String lastModified) {
		this.lastModified = lastModified;
	}
}
